import datetime

import requests
from django import http
from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.cache import cache_page
from django_redis import cache
from rest_framework import viewsets, mixins, status
from rest_framework.views import APIView

from XunShi.settings import es
from apps.articles.filters import ArticleFilter
from apps.articles.models import Article, Category, ArticleContent
from apps.articles.serializers import ArticleModelSerializer, CategoryModelSerializer, ESArticleModelSerializer
from apps.users.models import SearchHistory
from utils.my_permission import MyPermission
from utils.notifications import Notification
from utils.paginations import PageNum


@method_decorator(cache_page(60 * 15), name='dispatch')
class ArticleModelViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.UpdateModelMixin,
                          mixins.ListModelMixin, mixins.RetrieveModelMixin):
    serializer_class = ArticleModelSerializer
    queryset = Article.objects.all()
    pagination_class = PageNum
    permission_classes = [MyPermission]
    filter_class = ArticleFilter

    def create(self, request, *args, **kwargs):
        with transaction.atomic():
            try:
                save_id = transaction.savepoint()
                serializer = self.get_serializer(data=request.data)
                serializer.is_valid(raise_exception=True)
                self.perform_create(serializer)
                headers = self.get_success_headers(serializer.data)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'errmsg': e.__str__()})
        article = Article.objects.get(id=serializer.data['id'])
        data = ESArticleModelSerializer(article).data
        es.index(index='articles', body={
            'article_id': data['id'],
            'author_id': data['author_id'],
            'title': data['title'],
            'content': data['content'],
            'create_time': data['create_time'],
            'category': data['category']
        }, id=article.id)
        transaction.savepoint_commit(save_id)
        return http.JsonResponse({'message': 'OK', 'data': serializer.data}, status=status.HTTP_201_CREATED,
                                 headers=headers)


class CategoryView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        queryset = Category.objects.all()
        serializer = CategoryModelSerializer(queryset, many=True)
        return http.JsonResponse({'message': 'OK', 'data': serializer.data})


class ArticleContentView(APIView):
    permission_classes = [MyPermission]

    def get(self, request, article_id):
        try:
            content = ArticleContent.objects.get(article_id=article_id)
        except Exception as e:
            return http.JsonResponse({'message': e.__str__()})
        return http.JsonResponse({'message': "OK", 'data': content.content})


class CollectArticleView(APIView):
    def post(self, request, article_id):
        try:
            target_article = Article.objects.get(id=article_id)
            target_article.collection_users.add(request.user)
            target_article.save()
            # 发送收藏通知
            Notification('收藏', request.user, target_article.author, target_article).send_system_message()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '收藏失败.'})
        return http.JsonResponse({'message': 'OK'})

    def delete(self, request, article_id):
        try:
            Article.objects.get(id=article_id).collection_users.remove(request.user)
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '取消收藏失败.'})
        return http.JsonResponse({'message': 'OK'})


class ArticleAccessView(APIView):
    def put(self, request, article_id):
        try:
            new_click = request.data.get('clicks')
            article = Article.objects.get(id=article_id)
            article.clicks = new_click
            article.save()
        except Exception as e:
            print(e)
            return http.JsonResponse({'message': '添加访问数量失败'})
        return http.JsonResponse({'message': 'OK'})


class SearchView(APIView):
    permission_classes = [MyPermission]

    def get(self, request):
        q = request.query_params.get('q')
        page = request.query_params.get('page', None)
        per_page = request.query_params.get('per_page', None)
        page = 1 if page is None else int(page)
        per_page = int(per_page) if per_page else 10
        # Search from Elasticsearch
        query = {
            'from': (page - 1) * per_page,
            'size': per_page,
            '_source': False,
            'query': {
                "multi_match": {
                    "query": q,
                    "fields": ["title", "content", 'category']
                }
            }
        }
        ret = es.search(index='articles', body=query)

        total_count = ret['hits']['total']['value']

        hits = ret['hits']['hits']
        id_list = [i['_id'] for i in hits]
        print(id_list)
        queryset = Article.objects.filter(id__in=id_list)
        serializer = ArticleModelSerializer(queryset, many=True)
        # Record user search history
        # if request.user and page == 1:
        #     try:
        #         history = SearchHistory.objects.get(query=q, user=request.user)
        #         if history:
        #             history.create_time = datetime.datetime.now()
        #             history.save()
        #         else:
        #             SearchHistory.objects.create(query=q, user=request.user)
        #     except Exception as e:
        #         print(e)
        return JsonResponse(
            {'message': 'OK', 'total_count': total_count, 'page': page, 'per_page': per_page,
             'results': serializer.data})


class SuggestionView(APIView):
    """
    联想建议
    """
    permission_classes = [MyPermission]

    def get(self, request):
        """
        获取联想建议
        """
        q = request.query_params.get('q')
        if not q:
            return JsonResponse({'message': '请输入关键字'})
        # 先尝试自动补全建议查询
        query = {
            'from': 0,
            'size': 10,
            '_source': False,
            'suggest': {
                'word-completion': {
                    'prefix': q,
                    'completion': {
                        'field': 'suggest',
                        "fuzzy": {
                            "fuzziness": 2,
                            "unicode_aware": True
                        }
                    }
                },
            }
        }
        ret = es.search(index='completions', body=query)
        options = ret['suggest']['word-completion'][0]['options']

        # 如果没得到查询结果，进行纠错建议查询
        if not options:
            query = {
                'from': 0,
                'size': 10,
                '_source': False,
                'suggest': {
                    'word-phrase': {
                        'text': q,
                        'phrase': {
                            'field': 'content',
                            'size': 1
                        }
                    }
                }
            }
            ret = es.search(index='articles', body=query)
            options = ret['suggest']['word-phrase'][0]['options']

        results = []
        for option in options:
            if option['text'] not in results:
                results.append(option['text'])

        return JsonResponse({'message': 'OK', 'options': results})
